package mes.kanban.config;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * redis配置类
 * @author gjy
 *
 * 2018年1月16日下午4:34:44
 */

@Component
@Configuration
public class RedisConfig extends CachingConfigurerSupport{
	
	
	private static final Logger log = LoggerFactory.getLogger(RedisConfig.class);

	
	@Value("${spring.redis.url}")
	private String host;
	
	@Value("${spring.redis.port}")
	private int port;
	
	@Value("${spring.redis.timeout}")
	private int timeout;
	
	@Value("${spring.redis.pool.max-active}")
	private int maxTotal;
	
	@Value("${spring.redis.pool.max-wait}")
	private int maxWaitMillis;
	
	@Value("${spring.redis.pool.max-idle}")
	private int maxIdle;
	
	@Value("${spring.redis.pool.min-idle}")
	private int minIdle;
	
	@Bean(name="jedisPool")
	public JedisPool getRedisPool() {
		
		JedisPool pool = null;
		try {
			JedisPoolConfig poolConfig = new JedisPoolConfig();
			poolConfig.setMaxTotal(maxTotal);
			poolConfig.setMaxWaitMillis(maxWaitMillis);
			poolConfig.setMaxIdle(maxIdle);
			poolConfig.setMinIdle(minIdle);
			pool = new JedisPool(poolConfig,host, port);
			log.info("redis1成功打开============================,active:"+pool.getNumActive());
		} catch (Exception e) {
			log.error("redis1获取异常。。。。。。。。。。。。。。。。。。。。");
			e.printStackTrace();
		}
		
		return pool;
	}
	
	@Bean(name="jedis")
	public Jedis getJedis() {
		
		JedisPool pool = null;
		try {
			pool = new JedisPool(host, port);
			log.info("redis2成功打开============================");
		} catch (Exception e) {
			log.error("redis2获取异常。。。。。。。。。。。。。。。。。。。。");
			e.printStackTrace();
		}
		
		return pool.getResource();
	}
	

	@Bean 
	public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
	        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
	        return cacheManager;
	 }
	
	
	/**
	 * RedisTemplate缓存操作类,类似于jdbcTemplate的一个类;
	 * 
	 * 虽然CacheManager也能获取到Cache对象，但是操作起来没有那么灵活；
	 * 
	 * 这里在扩展下：RedisTemplate这个类不见得很好操作，我们可以在进行扩展一个我们
	 * 
	 * 自己的缓存类，比如：RedisStorage类;
	 * 
	 * @param factory : 通过Spring进行注入，参数在application.properties进行配置；
	 * @return
	 */
	
	 @Bean(name="redisTemplate")
	public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
	        StringRedisTemplate template = new StringRedisTemplate(factory);
	        setSerializer(template);//设置序列化工具
	        template.afterPropertiesSet();
	        return template;
	    }   
	    
	 @SuppressWarnings({ "rawtypes", "unchecked" })
     private void setSerializer(StringRedisTemplate template){
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
            template.setValueSerializer(jackson2JsonRedisSerializer);
     }	    

	 /**
		 * 自定义key.
		 * 此方法将会根据类名+方法名+所有参数的值生成唯一的一个key,即使@Cacheable中的value属性一样，key也会不一样。
		 */
		@Override
		public KeyGenerator keyGenerator() {
			System.out.println("RedisCacheConfig.keyGenerator()");
			return new KeyGenerator() {
				@Override
				public Object generate(Object o, Method method, Object... objects) {
					// This will generate a unique key of the class name, the method name 
					//and all method parameters appended.
					StringBuilder sb = new StringBuilder();
					sb.append(o.getClass().getName());
					sb.append(method.getName());
					for (Object obj : objects) {
						sb.append(obj.toString());
					}
					System.out.println("keyGenerator=" + sb.toString());
					return sb.toString();
				}
			};
		}
	

}
